/**
 * 
 */
package merisis.experiments.gcs;

import static java.lang.String.format;

/**
 * 
 * The instrument for Guess-Complement Search Experiments.
 * 
 * @author Chenggong Lv
 * 
 */
public class GCSEInstrument {
	
	public static boolean DEBUG = true; 

	public GCSEInstrument(String title, int scale) {
		this.scale = scale;
	}

	private String title;

	private boolean disabled = true;

	private int scale;

	public int mergedCount = 0;

	public int rountcount = 0;

	private int accesscount = 0;

	private double stepdiff = 0;

	private int[] hgAccess = new int[10];

	public void connect() {
		disabled = false;
	}

	public void shutdown() {
		disabled = true;
	}

	public void doAccess() {

		if (disabled)
			return;

		accesscount++;
	}

	public void merge(GCSEInstrument other) {

		groupAccess(other.accesscount);

		mergedCount++;
	}
	
	public int getAccessCount() {
		return accesscount;
	}
	
	public int getScale() {
		return scale;
	}

	public void groupAccess(int slot) {

		if (slot >= hgAccess.length) {
			int size = hgAccess.length + 10
					* ((slot - hgAccess.length) / 10 + 1);
			int[] nhg = new int[size];
			System.arraycopy(hgAccess, 0, nhg, 0, hgAccess.length);
			hgAccess = nhg;
		}

		hgAccess[slot]++;
	}

	private double averg(int[] hg) {

		int count = 0;
		double sum = 0;
		for (int i = hg.length - 1; i >= 0; i--) {

			int freq = hg[i];
			if (freq == 0)
				continue;
			count += freq;
			sum += i * freq;
		}

		return sum / count;
	}

	private double diff2(int[] hg) {

		int count = 0;
		double sum = 0;
		for (int i = hg.length - 1; i >= 0; i--) {

			int freq = hg[i];
			if (freq == 0)
				continue;

			count += freq;
			sum += i * i * freq;
		}

		return sum / count;
	}

	private int upper(int[] hg) {
		for (int i = hg.length - 1; i >= 0; i--) {
			if (hg[i] > 0)
				return i;
		}

		return 0;
	}

	private int lower(int[] hg) {
		for (int i = 0; i < hg.length; i++) {
			if (hg[i] > 0)
				return i;
		}

		return 0;
	}

	public void print() {
		StringBuilder sb = new StringBuilder();
		sb.append("[[[ " + title + " ]]]");

		if (mergedCount == 0)
			mergedCount = 1;

		double av = averg(hgAccess);
		double df = diff2(hgAccess) - av * av;
		sb.append(format("  access: av=%f, df=%f, [%d,%d]\n", av, df,
				lower(hgAccess), upper(hgAccess)));

		sb.append('\n');
		// printHist(hgAccess, sb);
		printHist2(hgAccess, sb);
		System.out.println(sb.toString());

	}

	void printHist(int[] hg, StringBuilder sb) {
		for (int i = hg.length - 1; i >= 0; i--) {
			int c = hg[i];
			if (c == 0)
				continue;

			sb.append(format("H%d:%d\n", i, hg[i]));
		}
	}

	void printHist2(int[] hg, StringBuilder sb) {

		int seqnum = 4;
		int seglen = scale / seqnum + 1;

		int[] slotids = new int[seqnum * 2];
		double[] slots = new double[seqnum * 2];
		int id = scale;
		for (int i = seqnum - 1; i >= 0 && id >= 0; i--) {
			slotids[i] = id;
			id -= seglen;
		}
		id = 2 * scale;
		for (int i = seqnum; i < slotids.length; i++) {
			slotids[i] = id;
			if (id > hg.length)
				break;
			id += scale;
		}

		id = 0;
		int nums = 0;
		for (int i = 0; i < hg.length; i++) {

			while (id < slotids.length && i > slotids[id]) {
				id++;
			}
			if (id >= slotids.length)
				id = slotids.length - 1;

			int c = hg[i];

			slots[id] += c;
			nums += c;
		}

		for (int i = 0; i < slotids.length; i++) {

			char ch = (i == seqnum - 1) ? '|' : ' ';
			sb.append(format("%8d%c", slotids[i], ch));
		}
		sb.append('\n');
		for (int i = 0; i < slotids.length; i++) {

			double per = (((double) slots[i]) / nums) * 100;
			sb.append(format("%8.2f ", per));
		}
		sb.append('\n');
		double less = 0.0;
		for (int i = 0; i < seqnum; i++) {
			double per = (((double) slots[i]) / nums) * 100;
			less += per;
		}
		double more = 0.0;
		for (int i = seqnum; i < slots.length; i++) {
			double per = (((double) slots[i]) / nums) * 100;
			more += per;
		}

		sb.append(format("<%.2f | %.2f>\n", less, more));
	}
}